# Attributes
The API for interacting with cart and checkout attributes.
```jsx
import {
Text,
reactExtension,
useAttributeValues,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [buyerSelectedFreeTShirt, tshirtSize] =
useAttributeValues([
'buyerSelectedFreeTShirt',
'tshirtSize',
]);
if (Boolean(buyerSelectedFreeTShirt) === true) {
return (
You selected a free t-shirt, size:{' '}
{tshirtSize}
);
}
return null;
}
```
```js
import {
extension,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(root, {attributes}) => {
attributes.subscribe(() => {
renderUI();
});
function renderUI() {
const buyerSelectedFreeTShirt =
attributes.current?.find(
(attr) =>
attr.key ===
'buyerSelectedFreeTShirt',
)?.value;
const tshirtSize = attributes.current?.find(
(attr) => attr.key === 'tshirtSize',
)?.value;
if (
Boolean(buyerSelectedFreeTShirt) === true
) {
root.replaceChildren(
root.createComponent(
Text,
undefined,
`You selected a free t-shirt, size: ${tshirtSize}`,
),
);
} else {
root.replaceChildren();
}
}
renderUI();
},
);
```
## StandardApi
The base API object provided to `purchase` extension targets.
### Docs_Standard_AttributesApi
### attributes
value: `StatefulRemoteSubscribable`
- Attribute: export interface Attribute {
/**
* The key for the attribute.
*/
key: string;
/**
* The value for the attribute.
*/
value: string;
}
The custom attributes left by the customer to the merchant, either in their cart or during checkout.
### Attribute
### key
value: `string`
The key for the attribute.
### value
value: `string`
The value for the attribute.
## Related
- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)
## Examples
The API for interacting with cart and checkout attributes.
You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.
```jsx
import {
reactExtension,
BlockStack,
Button,
Text,
useAttributeValues,
useApplyAttributeChange,
useInstructions,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [giftWrapValue] = useAttributeValues([
'giftWrap',
]);
const giftWrap = Boolean(giftWrapValue);
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
async function toggleGiftWrap() {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
}
return (
Gift wrapping:{' '}
{giftWrap ? 'Added' : 'Not set'}
);
}
```
```js
import {
extension,
BlockStack,
Button,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(
root,
{
attributes,
instructions,
applyAttributeChange,
},
) => {
let giftWrap = false;
const text = root.createComponent(Text);
const button = root.createComponent(Button, {
onPress: async () => {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
},
});
const blockStack = root.createComponent(
BlockStack,
{
spacing: 'tight',
},
[text, button],
);
attributes.subscribe(updateUI);
instructions.subscribe(updateUI);
function updateUI() {
giftWrap = Boolean(
attributes.current?.find(
(attr) => attr.key === 'giftWrap',
)?.value,
);
text.replaceChildren(
`Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
);
button.updateProps({
disabled:
!instructions.current?.attributes
?.canUpdateAttributes,
});
button.replaceChildren(
giftWrap
? 'Remove gift wrap'
: 'Add gift wrap',
);
}
updateUI();
root.append(blockstack);
},
);
```
## CheckoutApi
The API object provided to `purchase.checkout` extension targets.
### Docs_Checkout_AttributesApi
### applyAttributeChange
value: `(change: AttributeChange) => Promise`
- AttributeChange: AttributeUpdateChange | AttributeRemoveChange
- Attribute: export interface Attribute {
/**
* The key for the attribute.
*/
key: string;
/**
* The value for the attribute.
*/
value: string;
}
- AttributeChangeResult: AttributeChangeResultSuccess | AttributeChangeResultError
Performs an update on an attribute attached to the cart and checkout. If successful, this mutation results in an update to the value retrieved through the [`attributes`](https://shopify.dev/docs/api/checkout-ui-extensions/apis/attributes#standardapi-propertydetail-attributes) property.
> Note: This method will return an error if the [cart instruction](https://shopify.dev/docs/api/checkout-ui-extensions/apis/cart-instructions#standardapi-propertydetail-instructions) `attributes.canUpdateAttributes` is false, or the buyer is using an accelerated checkout method, such as Apple Pay, Google Pay, or Meta Pay.
### AttributeUpdateChange
Updates an attribute on the order. If an attribute with the provided key does not already exist, it gets created.
### key
value: `string`
Key of the attribute to add or update
### type
value: `"updateAttribute"`
- Attribute: export interface Attribute {
/**
* The key for the attribute.
*/
key: string;
/**
* The value for the attribute.
*/
value: string;
}
The type of the `AttributeUpdateChange` API.
### value
value: `string`
Value for the attribute to add or update
### Attribute
### key
value: `string`
The key for the attribute.
### value
value: `string`
The value for the attribute.
### AttributeRemoveChange
Removes an attribute on the order if an attribute with the provided key already exists.
### key
value: `string`
Key of the attribute to remove
### type
value: `"removeAttribute"`
- Attribute: export interface Attribute {
/**
* The key for the attribute.
*/
key: string;
/**
* The value for the attribute.
*/
value: string;
}
The type of the `AttributeRemoveChange` API.
### AttributeChangeResultSuccess
The returned result of a successful update to an attribute.
### type
value: `"success"`
The type of the `AttributeChangeResultSuccess` API.
### AttributeChangeResultError
The returned result of an unsuccessful update to an attribute with a message detailing the type of error that occurred.
### message
value: `string`
A message that explains the error. This message is useful for debugging. It is **not** localized, and therefore should not be presented directly to the buyer.
### type
value: `"error"`
The type of the `AttributeChangeResultError` API.
## Related
- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)
## Examples
The API for interacting with cart and checkout attributes.
You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.
```jsx
import {
reactExtension,
BlockStack,
Button,
Text,
useAttributeValues,
useApplyAttributeChange,
useInstructions,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [giftWrapValue] = useAttributeValues([
'giftWrap',
]);
const giftWrap = Boolean(giftWrapValue);
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
async function toggleGiftWrap() {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
}
return (
Gift wrapping:{' '}
{giftWrap ? 'Added' : 'Not set'}
);
}
```
```js
import {
extension,
BlockStack,
Button,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(
root,
{
attributes,
instructions,
applyAttributeChange,
},
) => {
let giftWrap = false;
const text = root.createComponent(Text);
const button = root.createComponent(Button, {
onPress: async () => {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
},
});
const blockStack = root.createComponent(
BlockStack,
{
spacing: 'tight',
},
[text, button],
);
attributes.subscribe(updateUI);
instructions.subscribe(updateUI);
function updateUI() {
giftWrap = Boolean(
attributes.current?.find(
(attr) => attr.key === 'giftWrap',
)?.value,
);
text.replaceChildren(
`Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
);
button.updateProps({
disabled:
!instructions.current?.attributes
?.canUpdateAttributes,
});
button.replaceChildren(
giftWrap
? 'Remove gift wrap'
: 'Add gift wrap',
);
}
updateUI();
root.append(blockstack);
},
);
```
## useApplyAttributeChange
Returns a function to mutate the `attributes` property of the checkout.
### UseApplyAttributeChangeGeneratedType
Returns a function to mutate the `attributes` property of the checkout.
#### Returns: (change: AttributeChange) => Promise
export function useApplyAttributeChange<
Target extends RenderExtensionTarget = RenderExtensionTarget,
>(): (change: AttributeChange) => Promise {
const api = useApi();
if ('applyAttributeChange' in api) {
return api.applyAttributeChange;
}
throw new ExtensionHasNoMethodError(
'applyAttributeChange',
api.extension.target,
);
}
### AttributeUpdateChange
Updates an attribute on the order. If an attribute with the provided key does not already exist, it gets created.
### key
value: `string`
Key of the attribute to add or update
### type
value: `"updateAttribute"`
- Attribute: export interface Attribute {
/**
* The key for the attribute.
*/
key: string;
/**
* The value for the attribute.
*/
value: string;
}
The type of the `AttributeUpdateChange` API.
### value
value: `string`
Value for the attribute to add or update
### Attribute
### key
value: `string`
The key for the attribute.
### value
value: `string`
The value for the attribute.
### AttributeRemoveChange
Removes an attribute on the order if an attribute with the provided key already exists.
### key
value: `string`
Key of the attribute to remove
### type
value: `"removeAttribute"`
- Attribute: export interface Attribute {
/**
* The key for the attribute.
*/
key: string;
/**
* The value for the attribute.
*/
value: string;
}
The type of the `AttributeRemoveChange` API.
### AttributeChangeResultSuccess
The returned result of a successful update to an attribute.
### type
value: `"success"`
The type of the `AttributeChangeResultSuccess` API.
### AttributeChangeResultError
The returned result of an unsuccessful update to an attribute with a message detailing the type of error that occurred.
### message
value: `string`
A message that explains the error. This message is useful for debugging. It is **not** localized, and therefore should not be presented directly to the buyer.
### type
value: `"error"`
The type of the `AttributeChangeResultError` API.
## Related
- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)
## Examples
The API for interacting with cart and checkout attributes.
You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.
```jsx
import {
reactExtension,
BlockStack,
Button,
Text,
useAttributeValues,
useApplyAttributeChange,
useInstructions,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [giftWrapValue] = useAttributeValues([
'giftWrap',
]);
const giftWrap = Boolean(giftWrapValue);
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
async function toggleGiftWrap() {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
}
return (
Gift wrapping:{' '}
{giftWrap ? 'Added' : 'Not set'}
);
}
```
```js
import {
extension,
BlockStack,
Button,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(
root,
{
attributes,
instructions,
applyAttributeChange,
},
) => {
let giftWrap = false;
const text = root.createComponent(Text);
const button = root.createComponent(Button, {
onPress: async () => {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
},
});
const blockStack = root.createComponent(
BlockStack,
{
spacing: 'tight',
},
[text, button],
);
attributes.subscribe(updateUI);
instructions.subscribe(updateUI);
function updateUI() {
giftWrap = Boolean(
attributes.current?.find(
(attr) => attr.key === 'giftWrap',
)?.value,
);
text.replaceChildren(
`Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
);
button.updateProps({
disabled:
!instructions.current?.attributes
?.canUpdateAttributes,
});
button.replaceChildren(
giftWrap
? 'Remove gift wrap'
: 'Add gift wrap',
);
}
updateUI();
root.append(blockstack);
},
);
```
## useAttributes
Returns the proposed `attributes` applied to the checkout.
### UseAttributesGeneratedType
Returns the proposed `attributes` applied to the checkout.
#### Returns: Attribute[] | undefined
export function useAttributes<
Target extends RenderExtensionTarget = RenderExtensionTarget,
>(): Attribute[] | undefined {
return useSubscription(useApi().attributes);
}
### Attribute
### key
value: `string`
The key for the attribute.
### value
value: `string`
The value for the attribute.
## Related
- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)
## Examples
The API for interacting with cart and checkout attributes.
You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.
```jsx
import {
reactExtension,
BlockStack,
Button,
Text,
useAttributeValues,
useApplyAttributeChange,
useInstructions,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [giftWrapValue] = useAttributeValues([
'giftWrap',
]);
const giftWrap = Boolean(giftWrapValue);
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
async function toggleGiftWrap() {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
}
return (
Gift wrapping:{' '}
{giftWrap ? 'Added' : 'Not set'}
);
}
```
```js
import {
extension,
BlockStack,
Button,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(
root,
{
attributes,
instructions,
applyAttributeChange,
},
) => {
let giftWrap = false;
const text = root.createComponent(Text);
const button = root.createComponent(Button, {
onPress: async () => {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
},
});
const blockStack = root.createComponent(
BlockStack,
{
spacing: 'tight',
},
[text, button],
);
attributes.subscribe(updateUI);
instructions.subscribe(updateUI);
function updateUI() {
giftWrap = Boolean(
attributes.current?.find(
(attr) => attr.key === 'giftWrap',
)?.value,
);
text.replaceChildren(
`Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
);
button.updateProps({
disabled:
!instructions.current?.attributes
?.canUpdateAttributes,
});
button.replaceChildren(
giftWrap
? 'Remove gift wrap'
: 'Add gift wrap',
);
}
updateUI();
root.append(blockstack);
},
);
```
## useAttributeValues
Returns the values for the specified `attributes` applied to the checkout.
### UseAttributeValuesGeneratedType
Returns the values for the specified `attributes` applied to the checkout.
#### Returns: (string | undefined)[]
#### Params:
- keys: string[]
export function useAttributeValues<
Target extends RenderExtensionTarget = RenderExtensionTarget,
>(keys: string[]): (string | undefined)[] {
const attributes = useAttributes();
if (!attributes?.length) {
return [];
}
return keys.map((key) => {
const attribute = attributes.find((attribute) => attribute.key === key);
return attribute?.value;
});
}
## Related
- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)
## Examples
The API for interacting with cart and checkout attributes.
You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.
```jsx
import {
reactExtension,
BlockStack,
Button,
Text,
useAttributeValues,
useApplyAttributeChange,
useInstructions,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [giftWrapValue] = useAttributeValues([
'giftWrap',
]);
const giftWrap = Boolean(giftWrapValue);
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
async function toggleGiftWrap() {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
}
return (
Gift wrapping:{' '}
{giftWrap ? 'Added' : 'Not set'}
);
}
```
```js
import {
extension,
BlockStack,
Button,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(
root,
{
attributes,
instructions,
applyAttributeChange,
},
) => {
let giftWrap = false;
const text = root.createComponent(Text);
const button = root.createComponent(Button, {
onPress: async () => {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
},
});
const blockStack = root.createComponent(
BlockStack,
{
spacing: 'tight',
},
[text, button],
);
attributes.subscribe(updateUI);
instructions.subscribe(updateUI);
function updateUI() {
giftWrap = Boolean(
attributes.current?.find(
(attr) => attr.key === 'giftWrap',
)?.value,
);
text.replaceChildren(
`Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
);
button.updateProps({
disabled:
!instructions.current?.attributes
?.canUpdateAttributes,
});
button.replaceChildren(
giftWrap
? 'Remove gift wrap'
: 'Add gift wrap',
);
}
updateUI();
root.append(blockstack);
},
);
```
## Examples
The API for interacting with cart and checkout attributes.
You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.
```jsx
import {
reactExtension,
BlockStack,
Button,
Text,
useAttributeValues,
useApplyAttributeChange,
useInstructions,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => ,
);
function Extension() {
const [giftWrapValue] = useAttributeValues([
'giftWrap',
]);
const giftWrap = Boolean(giftWrapValue);
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
async function toggleGiftWrap() {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
}
return (
Gift wrapping:{' '}
{giftWrap ? 'Added' : 'Not set'}
);
}
```
```js
import {
extension,
BlockStack,
Button,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(
root,
{
attributes,
instructions,
applyAttributeChange,
},
) => {
let giftWrap = false;
const text = root.createComponent(Text);
const button = root.createComponent(Button, {
onPress: async () => {
const result = giftWrap
? await applyAttributeChange({
type: 'removeAttribute',
key: 'giftWrap',
})
: await applyAttributeChange({
type: 'updateAttribute',
key: 'giftWrap',
value: 'true',
});
if (result.type === 'error') {
console.error(result.message);
}
},
});
const blockStack = root.createComponent(
BlockStack,
{
spacing: 'tight',
},
[text, button],
);
attributes.subscribe(updateUI);
instructions.subscribe(updateUI);
function updateUI() {
giftWrap = Boolean(
attributes.current?.find(
(attr) => attr.key === 'giftWrap',
)?.value,
);
text.replaceChildren(
`Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
);
button.updateProps({
disabled:
!instructions.current?.attributes
?.canUpdateAttributes,
});
button.replaceChildren(
giftWrap
? 'Remove gift wrap'
: 'Add gift wrap',
);
}
updateUI();
root.append(blockstack);
},
);
```